/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "Core/Commons.h"
#include "FpsSkyBoxSceneNode.h"
#include "CColladaDatabase.h"
#include "CColladaMeshSceneNode.h"
#include "Game/Utils/Utils.h"
#include "IColladaMesh.h"
#include "SceneManager/FpsColladaDatabase.h"
#include "Game/Camera/GameCamera.h"
#include "FpsCommonGLMaterialRenderer.h"

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

using namespace irr;
using namespace core;
using namespace scene;
using namespace video;

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

//! constructor
FpsSkyBoxSceneNode::FpsSkyBoxSceneNode(const char *meshFilename, s32 id)
	: ISceneNode(id)
{
	#ifdef _DEBUG
	setDebugName("FpsSkyBoxSceneNode");
	#endif

	setAutomaticCulling(scene::EAC_OFF);
	m_box.MaxEdge.set(0,0,0);
	m_box.MinEdge.set(0,0,0);

	m_node = ConstructColladaScene(meshFilename,true);
	irr::core::list<irr::scene::ISceneNodeAnimator*> anims = m_node->getAnimators();
	if(anims.getSize()>0)
	{
		irr::scene::ISceneNodeAnimator* anim = (*anims.begin());
		anim->getTimelineCtrl()->setLoop(true);
	}
	
	SkyboxNodeList.reallocate(32);

	collectSkyboxNodes(m_node);
	SkyboxNodeList.sort();
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

FpsSkyBoxSceneNode::~FpsSkyBoxSceneNode()
{
	if(m_node)
	{
		m_node->drop();
	}
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void FpsSkyBoxSceneNode::collectSkyboxNodes(irr::scene::ISceneNode*	node)
{
	if(node->getType() == ESNT_COLLADA_MESH)
	{
		SkyboxNodeList.push_back(node);
	}

	list<ISceneNode*> Children	=	node->getChildren();
	list<ISceneNode*>::Iterator childIt = Children.begin();
	for(; childIt != Children.end(); childIt++)
	{
		collectSkyboxNodes((*childIt));
	}
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

//! renders the node.
void FpsSkyBoxSceneNode::render(void* renderData)
{
	video::IVideoDriver*		driver	=	SceneManager->getVideoDriver();
	scene::ICameraSceneNode*	camera	=	SceneManager->getActiveCamera();

	if (!camera || !driver)
		return;

	{

		for(int i = 0; i < SkyboxNodeList.size(); i++)
		{
			CColladaMeshSceneNode*	meshNode	=	(CColladaMeshSceneNode*)SkyboxNodeList[i].Node;
			IColladaMesh*			mesh		=	(IColladaMesh*)meshNode->getMesh();

			matrix4 mat = meshNode->getAbsoluteTransformation();
			mat[12] += camera->getAbsolutePosition().X;
			mat[13] += camera->getAbsolutePosition().Y;
			mat[14] += camera->getAbsolutePosition().Z/2.0f;

			driver->setTransform(video::ETS_WORLD, mat);

	//and ???		mesh->onPrepareBuffersForRendering(IColladaMesh::EPBS_RENDERING);
			for(int i = 0; i < mesh->getMeshBufferCount(); i++)
			{
				scene::IMeshBuffer* mb = mesh->getMeshBuffer(i);
				if (mb)
				{
					video::SMaterial& material = meshNode->isReadOnlyMaterials() ? mb->getMaterial() : meshNode->getMaterial(i);
					material.setFlag(EMF_ZBUFFER, true);
					material.setFlag(EMF_ZWRITE_ENABLE, false);

					driver->setMaterial(material);
					driver->drawMeshBuffer(mb);

					material.setFlag(EMF_ZBUFFER, true);
					material.setFlag(EMF_ZWRITE_ENABLE, true);
				}
			}
		}
	}
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

//! renders the node in mirror.
void FpsSkyBoxSceneNode::renderMirror()
{
	video::IVideoDriver*		driver	= SceneManager->getVideoDriver();
	scene::ICameraSceneNode*	camera	= SceneManager->getActiveCamera();
	
	if (!driver || !camera)
		return;

	matrix4 view	= camera->getAbsoluteTransformation();
	vector3df front	= vector3df(view[2], view[6], view[10]).normalize();
	plane3df plane(vector3df(0.0f, 0.0f, 0.0f), vector3df(0.0f, 1.0f, 0.0f));

	{

		for(int i = 0; i < SkyboxNodeList.size(); i++)
		{
			CColladaMeshSceneNode*	meshNode	=	(CColladaMeshSceneNode*)SkyboxNodeList[i].Node;
			IColladaMesh*			mesh		=	(IColladaMesh*)meshNode->getMesh();

			matrix4 mat = meshNode->getAbsoluteTransformation();
			mat[12] += camera->getAbsolutePosition().X;
			mat[13] += camera->getAbsolutePosition().Y;
			mat[14] += camera->getAbsolutePosition().Z / 20.0f;
			//mat[14] += camera->getAbsolutePosition().Z / 2.0f;

			matrix4 reflexion;
			reflexion.buildReflexionMatrix(plane);

			mat *= reflexion;

			driver->setTransform(video::ETS_WORLD, mat);

	//and ???		mesh->onPrepareBuffersForRendering(IColladaMesh::EPBS_RENDERING);
			for(int i = 0; i < mesh->getMeshBufferCount(); i++)
			{
				scene::IMeshBuffer* mb = mesh->getMeshBuffer(i);
				if (mb)
				{
					SMaterial& material				= meshNode->isReadOnlyMaterials() ? mb->getMaterial() : meshNode->getMaterial(i);

					material.setFlag(EMF_BACK_FACE_CULLING, false);
					material.setFlag(EMF_ZBUFFER, false);
					material.setFlag(EMF_ZWRITE_ENABLE, false);

					driver->setMaterial(material);
					driver->drawMeshBuffer(mb);

					material.setFlag(EMF_ZBUFFER, true);
					material.setFlag(EMF_ZWRITE_ENABLE, true);

					material.setFlag(EMF_BACK_FACE_CULLING, true);
				}
			}
		}
	}
}


//! returns the axis aligned bounding box of this node
const core::aabbox3d<f32>& FpsSkyBoxSceneNode::getBoundingBox() const
{
	return m_node->getBoundingBox();
}


/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void FpsSkyBoxSceneNode::OnAnimate(irr::u32 timeMs)
{
	m_node->OnAnimate(timeMs);
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void FpsSkyBoxSceneNode::OnRegisterSceneNode()
{
	if (IsVisible)
		SceneManager->registerNodeForRendering(this, 0, (void*)1, ESNRP_SKY_BOX);

	ISceneNode::OnRegisterSceneNode();
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

//! Creates a clone of this scene node and its children.
ISceneNode* FpsSkyBoxSceneNode::clone(ISceneNode* newParent, ISceneManager* newManager)
{
	return 0;
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////